package com.fuyun.microservice.connect;


import com.fuyun.microservice.config.ClientPrivilegeProperties;
import com.fuyun.microservice.connect.pojo.ClientEndpoint;
import com.fuyun.microservice.utils.Constants;
import com.fuyun.microservice.utils.SessionState;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Slf4j
public class SessionManager {

    private final String hostName;
    private final ClientPrivilegeProperties clientPrivilegeProperties;
    private final SessionStore sessionStore;

    public SessionManager(ClientPrivilegeProperties clientPrivilegeProperties, SessionStore sessionStore) {
        this.clientPrivilegeProperties = clientPrivilegeProperties;
        this.sessionStore = sessionStore;
        hostName = getHostName();
        log.debug("hostname:" + hostName);
    }


    public boolean addChannel(int clientId, String secret, Channel ch) {
        ClientPrivilegeProperties.Privilege privilege = clientPrivilegeProperties.getPrivileges().stream()
                .filter(p -> p.getId() == clientId && p.getSecret().equals(secret)).findFirst().orElse(null);
        if (privilege == null) {
            return false;
        }

        ch.attr(Constants.attributeKey).set(SessionState.LOGIN);
        ClientEndpoint clientEndpoint = new ClientEndpoint();
        clientEndpoint.setClientId(clientId);
        clientEndpoint.setLoginTime(System.currentTimeMillis());
        clientEndpoint.setServerHostName(hostName);
        clientEndpoint.setTypes(parseTypes(privilege.getTypes()));
        fillClientInformation(clientEndpoint, ch);

        sessionStore.add(ch, clientEndpoint);

        //todo:处理积压的消息
        // 增加流量整形 ，每个连接每秒发送，接收消息数不超过配置的值
        //ch.pipeline().addBefore("FrameDecoder", "ChannelTrafficBefore",  new ChannelTrafficShapingHandler(1000, 1000, 250));

        bindHandler(ch.pipeline());
        return true;
    }

    public void removeChannel(Channel ch) {
        ch.attr(Constants.attributeKey).set(SessionState.DIS_CONNECT);
        sessionStore.remove(ch);
    }

    public List<ClientEndpoint> getChannels() {
        return sessionStore.all();
    }

    public ClientEndpoint getSession(Channel ch) {
        return sessionStore.getClient(ch);
    }

    public Channel getChannel(int clientId) {
        return sessionStore.getChannel(clientId);
    }

    /**
     * 连接建立成功后要加载的channelHandler
     */
    private void bindHandler(ChannelPipeline pipe) {
//        pipe.addFirst(new LoggingHandler(LogLevel.TRACE));
    }

    private static List<Integer> parseTypes(String str) {
        if (Strings.isNullOrEmpty(str)) {
            return Lists.newArrayList();
        }

        return Arrays.asList(str.split(",")).stream()
                .map(s -> Integer.parseInt(s)).collect(Collectors.toList());
    }


    public static String getHostName() {
        try {
            InetAddress ip = InetAddress.getLocalHost();
            return ip.getHostName();
        } catch (UnknownHostException e) {
            log.error("gethost error", e);
        }

        return "default-host";
    }

    private void fillClientInformation(final ClientEndpoint clientEndpoint, Channel channel) {
        InetSocketAddress socketAddress = (InetSocketAddress) channel.remoteAddress();
        clientEndpoint.setClientAddress(socketAddress.getAddress().getHostAddress());
        clientEndpoint.setClientHostName(socketAddress.getAddress().getHostName());
        clientEndpoint.setClientPort(socketAddress.getPort());
    }
}
